﻿#include "ObjConversioner.h"

ObjConversioner::ObjConversioner(void)
{
    initModel();
}

vector<string> ObjConversioner::split(const string& str, const string& delim)
{
    vector<string> res;
    if ("" == str)
        return res;

    char* strs = new char[str.length() + 1];
    strcpy(strs, str.c_str());

    char* d = new char[delim.length() + 1];
    strcpy(d, delim.c_str());

    char* p = strtok(strs, d);
    while (p)
    {
        string s = p;
        res.push_back(s);
        p = strtok(NULL, d);
    }
    return res;
}

void ObjConversioner::initModel()
{
    vertexs.clear();
    faceVertexCounts.clear();
    faceVertexIndices.clear();
}

int ObjConversioner::LoadObjModel(string _srcFilePath)
{
    ifstream myfile(_srcFilePath);
    if (!myfile.is_open())
    {
        cout << "Obj模型文件打开失败：" << _srcFilePath << endl;
        return -1;
    }

    initModel();

    string lineData;
    vector<point3f> normals;

    while (getline(myfile, lineData))
    {
        vector<string> lineItem = split(lineData, " ");

        if (lineItem.size() <= 0)
        {
            continue;
        }
        else if (lineItem[0] == "v" && lineItem.size() == 4)
        {
            vertex vertex;
            vertex.point.x = atof(lineItem[1].c_str());
            vertex.point.y = atof(lineItem[2].c_str());
            vertex.point.z = atof(lineItem[3].c_str());

            vertexs.push_back(vertex);
        }
        else if (lineItem[0] == "vn" && lineItem.size() == 4)
        {
            point3f normal;
            normal.x = atof(lineItem[1].c_str());
            normal.y = atof(lineItem[2].c_str());
            normal.z = atof(lineItem[3].c_str());

            normals.push_back(normal);
        }
        else if (lineItem[0] == "f")
        {
            faceVertexCounts.push_back(lineItem.size() - 1);

            for (int i = 1; i < lineItem.size(); ++i)
            {
                string indexData = lineItem[i];

                vector<string> indexItem = split(indexData, "/");
                faceVertexIndices.push_back(atoi(indexItem[0].c_str()) - 1); // usd顶点序号从0开始

                //判断是否使用顶点法线
                if (indexItem.size() == 3)
                {
                    vertexs[atoi(indexItem[0].c_str()) - 1].normal.x = normals[atoi(indexItem[2].c_str()) - 1].x;
                    vertexs[atoi(indexItem[0].c_str()) - 1].normal.y = normals[atoi(indexItem[2].c_str()) - 1].y;
                    vertexs[atoi(indexItem[0].c_str()) - 1].normal.z = normals[atoi(indexItem[2].c_str()) - 1].z;
                }
                else if (indexItem.size() == 2 && indexData.find("//") != indexData.npos)
                {
                    vertexs[atoi(indexItem[0].c_str()) - 1].normal.x = normals[atoi(indexItem[1].c_str()) - 1].x;
                    vertexs[atoi(indexItem[0].c_str()) - 1].normal.y = normals[atoi(indexItem[1].c_str()) - 1].y;
                    vertexs[atoi(indexItem[0].c_str()) - 1].normal.z = normals[atoi(indexItem[1].c_str()) - 1].z;
                }
            }
        }
    }
}

void ObjConversioner::printModelMesh()
{
    for (int i = 0; i < vertexs.size(); ++i)
    {
        vertex vertex = vertexs[i];
        cout << "point " << i << "\t:[" << vertex.point.x << "," << vertex.point.y << "," << vertex.point.z << "]";
        cout << "\tnormal "
             << ":[" << vertex.normal.x << "," << vertex.normal.y << "," << vertex.normal.z << "]" << endl;
    }

    for (int i = 0; i < faceVertexCounts.size(); ++i)
    {
        cout << "face " << i << "\t" << faceVertexCounts[i] << "[";
        for (int j = 0; j < faceVertexCounts[i] - 1; ++j)
        {
            cout << faceVertexIndices[i + j] << ",";
        }
        cout << faceVertexIndices[faceVertexCounts[i] - 1] << "]" << endl;
    }
}

int ObjConversioner::SaveUsdModel(string _dstFilePath)
{

    ofstream outfile(_dstFilePath, ios::trunc);
    if (!outfile.is_open())
    {
        cout << "Usd模型文件创建失败：" << _dstFilePath << endl;
        return -1;
    }

    outfile << "#usda 1.0" << endl;
    outfile << "def Mesh \"model\" {" << endl;

    //保存顶点信息
    point3f point;
    outfile << "\tpoint3f[] points = [";
    for (int i = 0; i < vertexs.size() - 1; ++i)
    {
        point = vertexs[i].point;
        outfile << "(" << point.x << "," << point.y << "," << point.z << "),";
    }
    point = vertexs[vertexs.size() - 1].point;
    outfile << "(" << point.x << "," << point.y << "," << point.z << ")]" << endl;

    //保存顶点法线信息
    point3f normal;
    outfile << "\tnormal3f[] normals = [";
    for (int i = 0; i < vertexs.size() - 1; ++i)
    {
        normal = vertexs[i].normal;
        outfile << "(" << normal.x << "," << normal.y << "," << normal.z << "),";
    }
    normal = vertexs[vertexs.size() - 1].normal;
    outfile << "(" << normal.x << "," << normal.y << "," << normal.z << ")]" << endl;

    //保存面-顶点数信息
    outfile << "\tint[] faceVertexCounts = [";
    for (int i = 0; i < faceVertexCounts.size() - 1; ++i)
    {
        outfile << faceVertexCounts[i] << ",";
    }
    outfile << faceVertexCounts[faceVertexCounts.size() - 1] << "]" << endl;

    //保存面-顶点索引信息
    outfile << "\tint[] faceVertexIndices = [";
    for (int i = 0; i < faceVertexIndices.size() - 1; ++i)
    {
        outfile << faceVertexIndices[i] << ",";
    }
    outfile << faceVertexIndices[faceVertexIndices.size() - 1] << "]" << endl;

    outfile << "}" << endl;
    outfile.close();
}

string ObjConversioner::GetBase64ModelMesh()
{
    size_t indexByteLength = faceVertexIndices.size() * sizeof(unsigned int);
    size_t pointsByteLength = vertexs.size() * sizeof(float) * 3;
    size_t sumByteLength = indexByteLength + pointsByteLength * 2;

    unsigned char *data = new unsigned char[sumByteLength]();
    unsigned char *temp = data;

    memset(temp, 0, sumByteLength);
    unsigned int *dataIndex = new unsigned int[faceVertexIndices.size()];
    for (int i = 0; i < faceVertexIndices.size(); ++i)
    {
        dataIndex[i] = faceVertexIndices[i];
    }
    memcpy(temp, dataIndex, sizeof(unsigned int) * faceVertexIndices.size());
    temp = temp + sizeof(unsigned int) * faceVertexIndices.size();

    float *dataPonit = new float[vertexs.size() * 3];
    for (int i = 0; i < vertexs.size(); ++i)
    {
        dataPonit[i * 3 + 0] = vertexs[i].point.x;
        dataPonit[i * 3 + 1] = vertexs[i].point.y;
        dataPonit[i * 3 + 2] = vertexs[i].point.z;
    }
    memcpy(temp, dataPonit, sizeof(float) * vertexs.size() * 3);
    temp = temp + sizeof(float) * vertexs.size() * 3;

    float *dataNormal = new float[vertexs.size() * 3];
    for (int i = 0; i < vertexs.size(); ++i)
    {
        dataNormal[i * 3 + 0] = vertexs[i].normal.x;
        dataNormal[i * 3 + 1] = vertexs[i].normal.y;
        dataNormal[i * 3 + 2] = vertexs[i].normal.z;
    }
    memcpy(temp, dataNormal, sizeof(float) * vertexs.size() * 3);

    Base64 *base = new Base64();
    string encoded = base->Encode(data, sumByteLength);

    return encoded;
}

int ObjConversioner::SaveglTFModel(string _dstFilePath)
{

    string meshData = "data:application/octet-stream;base64," + GetBase64ModelMesh();

    neb::CJsonObject oJson;
    oJson.AddEmptySubObject("asset");
    oJson.AddEmptySubArray("scenes");
    oJson.AddEmptySubArray("nodes");
    oJson.AddEmptySubArray("meshes");
    oJson.AddEmptySubArray("buffers");
    oJson.AddEmptySubArray("accessors");
    oJson.AddEmptySubArray("bufferViews");

    oJson["asset"].Add("version", "2.0");

    neb::CJsonObject scenesJson;
    scenesJson.AddEmptySubArray("nodes");
    scenesJson["nodes"].Add(0);
    oJson["scenes"].Add(scenesJson);

    neb::CJsonObject nodesJson;
    nodesJson.Add("mesh", 0);
    oJson["nodes"].Add(nodesJson);

    neb::CJsonObject primitivesJson;
    primitivesJson.AddEmptySubObject("attributes");
    primitivesJson["attributes"].Add("POSITION", 1); // Position属性用来描述顶点位置
    primitivesJson["attributes"].Add("NORMAL", 2);   // NORMAL属性用来描述顶点法线位置
    primitivesJson.Add("indices", 0);                //表示使用第一个accessor来解析该mesh

    neb::CJsonObject meshsJson;
    meshsJson.AddEmptySubArray("primitives");
    meshsJson["primitives"].Add(primitivesJson);
    oJson["meshes"].Add(meshsJson);

    neb::CJsonObject buffersJson;
    buffersJson.Add("uri", meshData);
    buffersJson.Add("byteLength", faceVertexIndices.size() * sizeof(unsigned int) + vertexs.size() * sizeof(float) * 6);
    oJson["buffers"].Add(buffersJson);

    //顶点索引bufferViews
    neb::CJsonObject indexBufferViewsJson;
    indexBufferViewsJson.Add("buffer", 0);
    indexBufferViewsJson.Add("byteOffset", 0);
    indexBufferViewsJson.Add("byteLength", faceVertexIndices.size() * sizeof(unsigned int));
    indexBufferViewsJson.Add("target", 34963); // 34963（ELEMENT_ARRAY_BUFFER）
    oJson["bufferViews"].Add(indexBufferViewsJson);

    //顶点坐标bufferViews
    neb::CJsonObject pointBufferViewsJson;
    pointBufferViewsJson.Add("buffer", 0);
    pointBufferViewsJson.Add("byteOffset", faceVertexIndices.size() * sizeof(unsigned int));
    pointBufferViewsJson.Add("byteLength", vertexs.size() * sizeof(float) * 3);
    pointBufferViewsJson.Add("target", 34962); // 34962（ARRAY_BUFFER）
    oJson["bufferViews"].Add(pointBufferViewsJson);

    //顶点法线坐标bufferViews
    neb::CJsonObject normalBufferViewsJson;
    normalBufferViewsJson.Add("buffer", 0);
    normalBufferViewsJson.Add("byteOffset", faceVertexIndices.size() * sizeof(unsigned int) + vertexs.size() * sizeof(float) * 3);
    normalBufferViewsJson.Add("byteLength", vertexs.size() * sizeof(float) * 3);
    normalBufferViewsJson.Add("target", 34962); // 34962（ARRAY_BUFFER）
    oJson["bufferViews"].Add(normalBufferViewsJson);

    //顶点索引accessor
    neb::CJsonObject indexAccessorsJson;
    indexAccessorsJson.Add("bufferView", 0);
    indexAccessorsJson.Add("byteOffset", 0);
    indexAccessorsJson.Add("count", faceVertexIndices.size());
    indexAccessorsJson.Add("componentType", 5125); // 5123（UNSIGNED_INT）
    indexAccessorsJson.Add("type", "SCALAR");      // SCALLAR（标量）、VEC3（矢量）、MAT4（矩阵）
    // indexAccessorsJson.Add("max", 34963);
    // indexAccessorsJson.Add("min", 34963);
    oJson["accessors"].Add(indexAccessorsJson);

    //顶点坐标accessor
    neb::CJsonObject pointAccessorJson;
    pointAccessorJson.Add("bufferView", 1);
    pointAccessorJson.Add("byteOffset", 0);
    pointAccessorJson.Add("count", vertexs.size());
    pointAccessorJson.Add("componentType", 5126); // 5126（FLOAT）
    pointAccessorJson.Add("type", "VEC3");        // SCALLAR（标量）、VEC3（矢量）、MAT4（矩阵）
    // accessorsJson.Add("max", 34963);
    // accessorsJson.Add("min", 34963);
    oJson["accessors"].Add(pointAccessorJson);

    //顶点法线坐标accessor
    neb::CJsonObject normalAccessorsJson;
    normalAccessorsJson.Add("bufferView", 2);
    normalAccessorsJson.Add("byteOffset", 0);
    normalAccessorsJson.Add("count", vertexs.size());
    normalAccessorsJson.Add("componentType", 5126); // 5126（FLOAT）
    normalAccessorsJson.Add("type", "VEC3");        // SCALLAR（标量）、VEC3（矢量）、MAT4（矩阵）
    // normalAccessorsJson.Add("max", 34963);
    // normalAccessorsJson.Add("min", 34963);
    oJson["accessors"].Add(normalAccessorsJson);

    ofstream outfile(_dstFilePath, ios::trunc);
    if (!outfile.is_open())
    {
        cout << "Usd模型文件创建失败：" << _dstFilePath << endl;
        return -1;
    }
    outfile << oJson.ToFormattedString() << endl;
    outfile.close();
}
